package com.seecoder.BlueWhale.serviceImpl;

import com.seecoder.BlueWhale.annotation.RoleAccessCheck;
import com.seecoder.BlueWhale.enums.CategoryEnum;
import com.seecoder.BlueWhale.enums.RoleEnum;
import com.seecoder.BlueWhale.exception.BlueWhaleException;
import com.seecoder.BlueWhale.po.Comment;
import com.seecoder.BlueWhale.po.Commodity;
import com.seecoder.BlueWhale.po.Store;
import com.seecoder.BlueWhale.po.User;
import com.seecoder.BlueWhale.repository.CommentRepository;
import com.seecoder.BlueWhale.repository.CommodityRepository;
import com.seecoder.BlueWhale.repository.StoreRepository;
import com.seecoder.BlueWhale.service.CommodityService;
import com.seecoder.BlueWhale.util.SecurityUtil;
import com.seecoder.BlueWhale.vo.CommentVO;
import com.seecoder.BlueWhale.vo.CommodityVO;
import com.seecoder.BlueWhale.vo.PageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CommodityServiceImpl implements CommodityService {
    @Autowired
    CommodityRepository commodityRepository;

    @Autowired
    SecurityUtil securityUtil;

    @Autowired
    StoreRepository storeRepository;

    @Autowired
    CommentRepository commentRepository;

    @Autowired
    StoreServiceImpl storeService;

    @Override
    @RoleAccessCheck(role = RoleEnum.STAFF)
    public CommodityVO create(CommodityVO commodityVO) {
        User user = securityUtil.getCurrentUser();
        Commodity newCommodity = commodityVO.toPO();
        if (newCommodity.getPhotoUrl().size() < 2){ //必须传入至少两张图片
            throw BlueWhaleException.commodityPhotosNeeded();
        }
        //根据当前stuff来设置商店id 在manager创建商店时也做了相似的处理
        Integer storeIdI = user.getStoreId();
        //在上面先检查工作人员是否有所属商店，无视这个warning，因为jpa需要接受int类型的参数，所以才进行类型转换。
        int storeId = storeIdI.intValue();
        newCommodity.setStoreId(storeId);
        newCommodity.setCreateTime(new Date());
        newCommodity.setCommentNumber(0);
        newCommodity.setRating(0);
        newCommodity.setExpectQuantity(newCommodity.getQuantity());
        commodityRepository.save(newCommodity);
        //在相应的商店的商品列表中添加该商品id
        Store store = storeRepository.findById(storeId);
        List<Integer> updateCommoditiesID = store.getCommoditiesID();
        updateCommoditiesID.add(newCommodity.getId());
        store.setCommoditiesID(updateCommoditiesID);
        storeRepository.save(store);
        return newCommodity.toVO();
    }

    @Override
    public CommodityVO info(int id) {
        Commodity commodity = commodityRepository.findById(id);
        if (commodity == null) {
            throw BlueWhaleException.cannotFindCommodity();
        } else {
            return commodity.toVO();
        }
    }


    @Override
    public boolean updateRating(int id) {
        List<Comment> commentList = commentRepository.findAllByCommodityID(id);
        Commodity commodity = commodityRepository.findById(id);
        float rating = 0;
        for (Comment comment : commentList)rating += comment.getRating();
        rating /= commentList.size();
        commodity.setRating(rating);
        commodity.setCommentNumber(commodity.getCommentNumber() + 1);//评论数加一（每次调用这个一定是多了一条评论，评论的同时就会更新）
        commodityRepository.save(commodity);
        storeService.updateRating(commodity.getStoreId()); //商品更新评分的时候商店同时要更新
        return true;
    }

    @Override
    public List<CommentVO> getComment(int id) {
        return commentRepository.findAllByCommodityID(id).stream().map(Comment::toVO).collect(Collectors.toList());
    }

    @Override
    public PageVO<CommodityVO> searchCommodity(Float maxPrice, Float minPrice, List<Integer> categories, String name, int page, int pageSz) {
        Specification<Commodity> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            // 添加价格范围查询条件
            if (maxPrice != null && minPrice != null) {
                predicates.add(criteriaBuilder.between(root.get("price"), minPrice, maxPrice));
            } else if (maxPrice != null) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("price"), maxPrice));
            } else if (minPrice != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("price"), minPrice));
            }

            // 添加商品类别查询条件
            if (categories != null && !categories.isEmpty()) {
                List<CategoryEnum> categoryEnums = categories.stream()
                        .map(CategoryEnum::valueOf)
                        .collect(Collectors.toList());
                predicates.add(root.get("category").in(categoryEnums));
            }

            // 添加商品名称模糊查询条件
            if (name != null && !name.isEmpty()) {
                predicates.add(criteriaBuilder.like(root.get("name"), "%" + name + "%"));
            }

            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        // 使用Specification进行查询，并将结果转换为CommodityVO列表
        List<Commodity> commodities = commodityRepository.findAll(specification);

        List<CommodityVO> commodityVOList = commodities.stream().map(Commodity::toVO).collect(Collectors.toList());
        return new PageVO<>(commodityVOList, page, pageSz);
    }

    @Override
    @RoleAccessCheck(role = RoleEnum.STAFF)
    public boolean changeQuantity(Integer ID, Integer newQuantity) {
        if (ID == null){
            throw BlueWhaleException.CommodityIdNotGiven();
        }
        int id = ID.intValue();
        Commodity updateCommodity = commodityRepository.findById(id);
        if (updateCommodity == null){
            throw BlueWhaleException.cannotFindCommodity();
        }
        int diff = updateCommodity.getQuantity() - updateCommodity.getExpectQuantity();
        updateCommodity.setExpectQuantity(newQuantity - diff);
        updateCommodity.setQuantity(newQuantity);
        commodityRepository.save(updateCommodity);
        return true;
    }
}